import { normalizeClass } from '@vue/shared'
import { defineComponent, getCurrentInstance, VNodeChild, App, PropType, cloneVNode, ref, watchSyncEffect } from 'vue'
import { getComponent, hasProp, isValidElement } from '../_util/props-util'
import useMemo from '../_util/hooks/useMemo'

import Trigger from '../trigger'

import placements from './placements'
import tooltipProps from '../tooltip/tooltipProps'
import ExpandTransition from '../expand-transition'

const prefixCls = 'x-dropdown'

const Dropdown = defineComponent({
  name: prefixCls,
  props: {
    ...tooltipProps,
    placement: { type: String as PropType<keyof typeof placements>, default: 'bottomLeft' },
    popup: [String, Number, Object, Array] as PropType<VNodeChild>,
    hasBg: { type: Boolean, default: true },
  },
  emits: ['update:visible', 'visibleChange'],
  slots: ['popup'],
  setup(props, { emit, slots }) {
    const { proxy: vm } = getCurrentInstance()
    const visibleRef = useMemo(() => props.visible)

    function setVisible(visible: boolean) {
      if (!hasProp(vm, 'visible')) {
        visibleRef.value = visible
      }
      emit('update:visible', visible)
      emit('visibleChange', visible)
    }

    let popupPoint: object
    let onAfterLeave: Function
    function onContextmenu(e: MouseEvent) {
      if (!props.trigger.includes('contextmenu')) return
      
      if (visibleRef.value) {
        visibleRef.value = false
        onAfterLeave = () => {
          console.log('() => {}');
          
          popupPoint = { pageX: e.pageX, pageY: e.pageY }
          visibleRef.value = true
          onAfterLeave = null
        }
      } else {
        popupPoint = { pageX: e.pageX, pageY: e.pageY }
        visibleRef.value = true
      }
    }
    function onPopupVisibleChange(visible: boolean) {
      if (!visible) setVisible(visible)
      else if (props.trigger.includes('contextmenu')) return
      else setVisible(visible)
    }
    function onClick() {
      onPopupVisibleChange(false)
    }
    function preventContextmenu(e: MouseEvent) {
      if (!props.trigger.includes('contextmenu')) return
      e.preventDefault()
    }

    const h = h => h * .5
    function PopupTransition(_, { slots }) {
      return <ExpandTransition appear name={prefixCls} height={h} onAfterLeave={onAfterLeave} v-slots={slots}  />
    }

    function getPopup() {
      const popupProps = {
        selectable: false,
        onClick,
        onContextmenu: preventContextmenu
      }
      let popup = getComponent(vm, 'popup')
      popup = Array.isArray(popup) ? popup[0] : popup
      popup = isValidElement(popup) ? popup : <div>{popup}</div>
      popup = cloneVNode(popup, popupProps)
      return <div>{popup}</div>
    }
    
    return () => {
      const { trigger, placement, builtinPlacements, disabled } = props

      const popupClass = normalizeClass([
        `${prefixCls} ${prefixCls}-placement-${props.placement}`,
        props.hasBg && `${prefixCls}-has-bg`,
        props.placement.includes('bottom') && `${prefixCls}-bottom`,
        props.popupClass
      ])

      const triggerProps = {
        prefixCls,
        action: disabled ? '' : trigger,
        popup: getPopup(),
        popupVisible: visibleRef.value,
        popupClass: popupClass,
        popupTransition: PopupTransition,
        popupAlign: props.align,
        popupPoint,
        popupStyle: props.popupStyle,
        disabledAlignInTransiting: true,
        popupPlacement: placement,
        builtinPlacements: builtinPlacements || placements,
        getPopupContainer: props.getPopupContainer,
        onPopupVisibleChange,
        mouseEnterDelay: props.mouseEnterDelay,
        mouseLeaveDelay: props.mouseLeaveDelay,
        alignPoint: trigger.includes('contextmenu'),
        onContextmenu
      }

      return (
        <Trigger {...triggerProps} v-slots={slots}></Trigger>
      )
    }
  }
})

Dropdown.install = (app: App) => {
  app.component(Dropdown.name, Dropdown)
}

export default Dropdown